/**
 * 
 */
package edu.umd.clip.lm.model.data;

import edu.umd.clip.lm.factors.*;
import edu.umd.clip.lm.util.GrowingOutputBuffer;

import java.util.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.regex.*;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class Context implements Cloneable, Serializable, Externalizable {
	static final long serialVersionUID = 1L;
	public long[] data;
	private final static Pattern split_re = Pattern.compile(" ");
	
	public Context(int order) {
		data = new long[order-1];
	}
	
	public Context(long[] data) {
		this.data = data;
	}
	
	public Context(ObjectInput in) throws IOException {
		read(in);
	}
	
	public Context(DataInput in) throws IOException {
		read(in);
	}
	
	public Context(ByteBuffer buffer) {
		read(buffer);
	}
	public Context(String valueString) {
		String tupleStrings[] = split_re.split(valueString);
		data = new long[tupleStrings.length];
		for(int i=0; i<data.length; ++i) {
			data[i] = FactorTuple.factorTuple(tupleStrings[i]);
		}
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	@Override
	public Object clone() {
		return new Context(data.clone());
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		return obj.getClass() == Context.class && Arrays.equals(data, ((Context)obj).data);
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return Arrays.hashCode(data);
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(FactorTuple.toString(data[0]));
		for(int i=1; i<data.length; ++i) {
			sb.append(' ');
			sb.append(FactorTuple.toString(data[i]));
		}
		return sb.toString();
	}
	
	public String toStringNoNull() {
		StringBuilder sb = new StringBuilder(FactorTuple.toStringNoNull(data[0]));
		for(int i=1; i<data.length; ++i) {
			sb.append(' ');
			sb.append(FactorTuple.toStringNoNull(data[i]));
		}
		return sb.toString();
	}
	
	public String toValueString() {
		StringBuilder sb = new StringBuilder(FactorTuple.toValueString(data[0]));
		for(int i=1; i<data.length; ++i) {
			sb.append(' ');
			sb.append(FactorTuple.toValueString(data[i]));
		}
		return sb.toString();
	}

	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
		read(in);
	}
	
	public void read(DataInput in) throws IOException {
		byte order = in.readByte();
		data = new long[order-1];
		for(byte i=0; i<data.length; ++i) {
			data[i] = in.readLong();
		}
	}

	public void read(ByteBuffer buffer) {
		byte order = buffer.get();
		data = new long[order-1];
		for(byte i=0; i<data.length; ++i) {
			data[i] = buffer.getLong();
		}		
	}
	
	public void writeExternal(ObjectOutput out) throws IOException {
		write(out);
	}
	
	public void write(DataOutput out) throws IOException {
		out.writeByte((byte) data.length + 1);
		for(int i=0; i<data.length; ++i) {
			out.writeLong(data[i]);
		}
	}
	
	public void write(GrowingOutputBuffer buffer) {
		buffer.put((byte) (data.length + 1));
		for(int i=0; i<data.length; ++i) {
			buffer.putLong(data[i]);
		}
	}
	
	public byte getOrder() {
		return (byte) (data.length+1);
	}
}
